﻿using System;
using System.ComponentModel;
using System.Linq;
using System.Security.Principal;
using System.Windows.Forms;
using System.Xml.Serialization;
using Microsoft.TeamFoundation.VersionControl.Client;

namespace TfsComLib.TfsConnection
{
    /// <summary>
    ///     Для хранения данных о workspace
    ///     Для хранения объекта workspace
    /// </summary>
    public class TfsWorkspaceData : INotifyPropertyChanged, IDisposable
    {
        private const string prefix = "TempWs_";
        private bool disposed;

        /// <summary>
        ///     Временный workspace // то есть создается при создании
        ///     и при вызове операции CreateTempWorkspace
        /// </summary>
        private bool isTemporary;

        /// <summary>
        ///     Данные о соединении с TFS
        /// </summary>
        private TfsConnectionData tfsConnectionData;

        /// <summary>
        ///     Selected workspace for merge works
        /// </summary>
        private Workspace workspace;

        /// <summary>
        ///     Имя workspace
        /// </summary>
        private string workspaceName;

        /// <summary>
        ///     Конструктор
        /// </summary>
        /// <param name="tfsConnectionData">Соединение к TFS</param>
        public TfsWorkspaceData(TfsConnectionData tfsConnectionData)
            : this()
        {
            TfsConnectionData = tfsConnectionData;
        }

        /// <summary>
        ///     Конструктор для сериализации
        /// </summary>
        /// <param name="tfsConnectionData">Соединение к TFS</param>
        public TfsWorkspaceData()
        {
            WorkspaceTempRoot = @"C:\test";
        }

        public string WorkspaceName
        {
            get { return workspaceName; }
            set
            {
                {
                    workspaceName = value;
                }
            }
        }

        public bool IsTemporary
        {
            get { return isTemporary; }
            set
            {
                if (value && (isTemporary == false))
                {
                    CreateTempWorkspace();
                }
                else if ((value == false) && isTemporary)
                {
                    DropTempWorkspace();
                }
                NotifyPropertyChange("IsTemporary");
                isTemporary = value;
            }
        }

        /// <summary>
        ///     Папка, которая должна быть корневой для временных workspace
        /// </summary>
        public string WorkspaceTempRoot { get; set; }

        public TfsConnectionData TfsConnectionData
        {
            get { return tfsConnectionData; }
            set
            {
                tfsConnectionData = value;
                tfsConnectionData.PropertyChanged += tfsConnectionData_PropertyChanged;
            }
        }


        [XmlIgnore]
        public Workspace Workspace
        {
            get
            {
                if (workspace == null)
                {
                    if (!string.IsNullOrEmpty(WorkspaceName))
                    {
                        workspace = (from selectedWorkspace in Workspaces
                            where selectedWorkspace.Name == WorkspaceName
                            select selectedWorkspace).FirstOrDefault();
                    }
                    else
                    {
                        if (Workspaces != null)
                        {
                            workspace = Workspaces.FirstOrDefault();
                        }
                        else
                        {
                            workspace = null;
                        }
                    }
                }
                return workspace;
            }
            set
            {
                if (!isTemporary)
                {
                    workspace = value;
                    if (value != null)
                    {
                        workspaceName = value.Name;
                    }
                    else
                    {
                        workspaceName = null;
                    }
                    NotifyPropertyChange("Workspace");
                    NotifyPropertyChange("WorkspaceName");
                }
            }
        }


        /// <summary>
        ///     Возвращает список локальных workspaces
        /// </summary>
        [XmlIgnore]
        public Workspace[] Workspaces
        {
            get
            {
                if (TfsConnectionData == null) return null;
                var VCServer = TfsConnectionData.GetVersionControlServer();
                if (VCServer == null)
                {
                    return null;
                }
                try
                {
                    var windowsIdentity = WindowsIdentity.GetCurrent();
                    var workspaces = VCServer.QueryWorkspaces(null, windowsIdentity.Name,
                        SystemInformation.ComputerName);
                    return workspaces;
                }
                catch
                {
                    return null;
                }
            }
            set { }
        }

        #region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        private void tfsConnectionData_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsConnected")
            {
                if (TfsConnectionData.IsConnected)
                {
                    NotifyPropertyChange("Workspaces");
                }
            }
        }

        public Workspace CreateWorkspace(string workspaceName, string workingFolderPath)
        {
            if (TfsConnectionData == null) return null;
            var VCServer = TfsConnectionData.GetVersionControlServer();
            var workspace = VCServer.CreateWorkspace(workspaceName);
            var serverFolder = "$/";
            var workingFolder = new WorkingFolder(serverFolder, workingFolderPath);
            workspace.CreateMapping(workingFolder);
            return workspace;
        }

        /// <summary>
        ///     Сгенерировать имя для временного workspace
        /// </summary>
        /// <returns></returns>
        private string GenerateWorkspaceTempName()
        {
            return prefix + DateTime.Now.ToString("ddMMyy_HHmmss_fff");
        }

        /// <summary>
        ///     Создать временный workspace
        /// </summary>
        /// <returns></returns>
        public Workspace CreateTempWorkspace()
        {
            try
            {
                WorkspaceName = GenerateWorkspaceTempName();
                Workspace = CreateWorkspace(WorkspaceName, WorkspaceTempRoot + "\\" + WorkspaceName);
                NotifyPropertyChange("Workspaces");
                NotifyPropertyChange("Workspace");
                isTemporary = true;
                return Workspace;
            }
            catch (Exception)
            {
                Workspace = null;
                return null;
            }
        }


        public void DropTempWorkspace()
        {
            if (isTemporary && (Workspace != null) && (Workspace.Name.StartsWith(prefix)))
            {
                try
                {
                    Workspace.Delete();
                }
                catch
                {
                }
                Workspace = null;
                NotifyPropertyChange("Workspaces");
                NotifyPropertyChange("WorkspaceName");
                isTemporary = false;
            }
        }

        /// <summary>
        ///     Уведомляет слушателей об изменении свойства
        /// </summary>
        /// <param name="prop"></param>
        private void NotifyPropertyChange(string prop)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(prop));
            }
        }

        private void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if ((isTemporary) && (disposing))
                {
                    DropTempWorkspace();
                }
                disposed = true;
            }
        }

        ~TfsWorkspaceData()
        {
            Dispose(false);
        }
    }
}